﻿using System.Linq;
using System.Text;
using Microsoft.Tools.WindowsInstallerXml.Bootstrapper;

namespace Wix.Win8SetupBootstrapper.ViewModels
{
    public sealed class ProgressPageViewModel : PageViewModelBase
    {
        private int _progress;
        private string _packageDownloadName;
        private int _downloadProgress;
        private int _installProgress;
        private bool _isProcessing;
        private string _packageInstallName;

        public ProgressPageViewModel(RootViewModel rootViewModel)
            : base(rootViewModel)
        {
            InitEvents();

            foreach (var package in this.RootViewModel.PackagesList)
            {
                if (!package.IsSelected)
                    continue;

                var msiPackage =
                    this.RootViewModel.Configuration.Ui.Pages.FeaturePage.FeatureDetails.FirstOrDefault(
                        e => e.PackageId == package.PackageId);

                if (msiPackage == null)
                    continue;


                if (package.FeaturesList.TrueForAll(e => e.IsSelected))
                {
                    this.WriteVariableToBundle(msiPackage.WixVariable, "ALL");
                }
                if (package.FeaturesList.TrueForAll(e => !e.IsSelected))
                {
                    package.IsSelected = false;
                }
                else
                {
                    var featuresToInstall = new StringBuilder();

                    foreach (var feature in package.FeaturesList.Where(e => e.IsSelected))
                    {
                        featuresToInstall.AppendFormat("{0},", feature.FeatureId);
                    }

                    this.WriteVariableToBundle(msiPackage.WixVariable,
                        featuresToInstall.Remove(featuresToInstall.ToString().LastIndexOf(','), 1).ToString());
                }
            }

            IsProcessing = true;

            this.CanCancel = true;
            this.CanBack = false;
            this.CanNext = false;

            this.RootViewModel.PlanAction(LaunchAction.Install);
        }

        private void InitEvents()
        {
            this.Bootstrapper.CacheAcquireProgress += Bootstrapper_CacheAcquireProgress;
            this.Bootstrapper.CacheAcquireBegin += Bootstrapper_CacheAcquireBegin;
            this.Bootstrapper.CacheAcquireComplete += Bootstrapper_CacheAcquireComplete;
            this.Bootstrapper.ExecutePackageBegin += Bootstrapper_ExecuteBegin;
            this.Bootstrapper.ExecuteMsiMessage += Bootstrapper_ExecuteMsiMessage;
            this.Bootstrapper.PlanPackageBegin += Bootstrapper_PlanPackageBegin;
            this.Bootstrapper.ExecuteProgress += Bootstrapper_ExecuteProgress;

        }

        void Bootstrapper_ExecuteProgress(object sender, ExecuteProgressEventArgs e)
        {
            this.InstallProgress = e.ProgressPercentage;

            this.Progress = (this.DownloadProgress + this.InstallProgress) / 2;
            e.Result = this.RootViewModel.IsCancelled ? Result.Cancel : Result.Ok;
        }

        void Bootstrapper_ExecuteMsiMessage(object sender, ExecuteMsiMessageEventArgs e)
        {

        }

        void Bootstrapper_PlanPackageBegin(object sender, PlanPackageBeginEventArgs e)
        {
            var package = this.RootViewModel.PackagesList.FirstOrDefault(x => x.PackageId == e.PackageId);

            if (package == null || !package.IsSelected)
            {
                e.State = RequestState.None;
            }
        }

        private void Bootstrapper_ExecuteBegin(object sender, ExecutePackageBeginEventArgs executePackageBeginEventArgs)
        {
            var package =
                this.RootViewModel.PackagesList.First(x => x.PackageId == executePackageBeginEventArgs.PackageId);
            this.PackageInstallName = package.DisplayName;
        }

        void Bootstrapper_CacheAcquireComplete(object sender, CacheAcquireCompleteEventArgs e)
        {
            this.DownloadProgress = 100;
            this.Progress = (this.DownloadProgress + this.InstallProgress) / 2;
        }

        void Bootstrapper_CacheAcquireBegin(object sender, CacheAcquireBeginEventArgs e)
        {
            this.DownloadProgress = 0;
            var package =
                this.RootViewModel.PackagesList.First(x => x.PackageId == e.PackageOrContainerId);
            this.PackageDownloadName = package.DisplayName;
        }

        private void Bootstrapper_CacheAcquireProgress(object sender,
            CacheAcquireProgressEventArgs e)
        {
            this.DownloadProgress = e.OverallPercentage / this.Bootstrapper.Engine.PackageCount;
            this.DownloadProgress = this.DownloadProgress;
            this.Progress = (this.DownloadProgress + this.InstallProgress) / 2;
            e.Result = this.RootViewModel.IsCancelled ? Result.Cancel : Result.Ok;
        }

        public int Progress
        {
            get { return _progress; }
            set
            {
                _progress = value;
                OnPropertyChanged();
            }
        }

        public string PackageDownloadName
        {
            get { return _packageDownloadName; }
            set { _packageDownloadName = value; OnPropertyChanged(); }
        }

        public string PackageInstallName
        {
            get { return _packageInstallName; }
            set { _packageInstallName = value; OnPropertyChanged(); }
        }

        public int DownloadProgress
        {
            get { return _downloadProgress; }
            set
            {
                _downloadProgress = value;
                OnPropertyChanged();
            }
        }

        public int InstallProgress
        {
            get { return _installProgress; }
            set { _installProgress = value; OnPropertyChanged(); }
        }

        public bool IsProcessing
        {
            get { return _isProcessing; }
            set { _isProcessing = value; OnPropertyChanged(); }
        }




    }
}